package tinynio;

import java.io.IOException;
import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.util.concurrent.Executor;

public abstract class AbstractCommunicator implements Communicator {

	protected Select select;

	private final SelectableChannel ch;
	protected final int interestOp;
	protected volatile SelectionKey selectionKey;

	public AbstractCommunicator(Select select, SelectableChannel ch, int interestOp) throws IOException {
		this.select = select;
		this.ch = ch;
		this.interestOp = interestOp;

		ch.configureBlocking(false);
	}

	@Override
	public void close() {
		try {
			ch.close();
			selectionKey.cancel();
			selectionKey = null;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void register() {
		select.execute(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println("register " + interestOp);
					selectionKey = ch.register(select.getSelector(), interestOp, AbstractCommunicator.this);
				} catch (ClosedChannelException e) {
					e.printStackTrace();
					close();
				}
			}
		});
	}

	protected void interest(int op) {
		selectionKey.interestOps(op);
	}

	@Override
	public abstract void connect(SocketAddress remote) throws IOException;

	@Override
	public abstract void bind(SocketAddress local) throws IOException;

	@Override
	public abstract void write(Object obj) throws IOException;

	@Override
	public abstract void flush() throws IOException;

	@Override
	public abstract void read() throws IOException;

	@Override
	public Executor executor() {
		return select.service();
	}

	public SelectableChannel channel() {
		return ch;
	}

}
